// $Id: test_list.cpp 9 2008-09-30 03:21:47Z rodlima $

#define BOOST_TEST_MODULE list
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#include <climits>
#include <boost/test/unit_test.hpp>
#include <list.h>
#include <object.h>
#include <metainfo.h>

using namespace orm;

struct Teste : object<Teste>/*{{{*/
{
    Teste(Teste &&that) 
        : object<Teste>(std::move(that))
        , dados(std::move(that.dados))
        , name(std::move(that.name)) {}

    Teste(ident id=0) : object<Teste>(id) {}
    std::vector<int> dados;
    std::string name;

    static metainfo<Teste> meta;
};
metainfo<Teste> Teste::meta = metainfo<Teste>("Teste")
                                .ident("idteste")
                                .member(&Teste::name, "name");
/*}}}*/

BOOST_TEST_DONT_PRINT_LOG_VALUE(list<Teste>::iterator)
BOOST_TEST_DONT_PRINT_LOG_VALUE(list<Teste>::const_iterator)

BOOST_AUTO_TEST_CASE(list_insert_lvalue)/*{{{*/
{
    Teste obj(3);
    obj.name = "name1";
    list<Teste> objs;
    objs.insert(obj);
    
    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(objs.begin()->name, "name1");
    BOOST_CHECK_PREDICATE(std::not_equal_to<Teste*>(),(&obj)(&*objs.begin()));
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_insert_rvalue)/*{{{*/
{
    list<Teste> objs;
    objs.insert(Teste(3));
    
    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(objs.begin()->id, 3);
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_insert_rvalue_move)/*{{{*/
{
    Teste obj(3);
    obj.dados = std::vector<int>(10,10);

    list<Teste> objs;
    objs.insert(std::move(obj));
    
    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(obj.dados.empty(), true);
    BOOST_CHECK_EQUAL(objs.begin()->id, 3);
    BOOST_CHECK_EQUAL(objs.begin()->dados.size(), 10);
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_insert_shared_ptr)/*{{{*/
{
    std::shared_ptr<Teste> obj(new Teste(3));
    obj->name = "name1";
    list<Teste> objs;
    objs.insert(obj);

    BOOST_CHECK_EQUAL(objs.insert(obj).second,false);

    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(objs.begin()->name, "name1");
    BOOST_CHECK_EQUAL(obj.use_count(), 2);
    BOOST_CHECK_EQUAL(obj.get(), &*objs.begin());
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_insert_weak_ptr)/*{{{*/
{
    std::shared_ptr<Teste> obj(new Teste(3));
    obj->name = "name1";
    list<Teste> objs;
    objs.insert_weak(std::weak_ptr<Teste>(obj));

    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(objs.begin()->name, "name1");
    BOOST_CHECK_EQUAL(obj.use_count(), 1);
    BOOST_CHECK_EQUAL(obj.get(), &*objs.begin());

    obj.reset();
    BOOST_CHECK_EQUAL(objs.size(), 0);
}/*}}}*/

BOOST_AUTO_TEST_CASE(list_find_id)/*{{{*/
{
    list<Teste> objs;

    Teste obj1(1), obj2(2), obj3(3);
    objs.insert(obj1);
    objs.insert(obj2);
    objs.insert(obj3);

    list<Teste>::const_iterator it = objs.find(2);
    BOOST_CHECK_EQUAL(it, ++objs.begin());

    BOOST_CHECK_EQUAL(objs.find(10), objs.end());
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_find_obj)/*{{{*/
{
    list<Teste> objs;

    Teste obj1(1), obj2(2), obj3(3);
    objs.insert(obj1);
    objs.insert(obj2);
    objs.insert(obj3);

    list<Teste>::const_iterator it = objs.find(obj2);
    BOOST_CHECK_EQUAL(it, ++objs.begin());

    BOOST_CHECK_EQUAL(objs.find(Teste(11)), objs.end());
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_find_obj_id0)/*{{{*/
{
    list<Teste> objs;

    Teste obj1(1), obj2(2), obj3(3);
    objs.insert(obj1);
    objs.insert(obj2);
    objs.insert(obj3);

    std::shared_ptr<Teste> pobj0(new Teste);
    objs.insert(pobj0);
    list<Teste>::iterator it = objs.find(*pobj0);
    BOOST_CHECK_PREDICATE(std::not_equal_to<list<Teste>::iterator>(),(it)(objs.end()));

    Teste obj0;
    objs.insert(obj0);
    BOOST_CHECK_EQUAL(objs.find(obj0), objs.end());
}/*}}}*/

BOOST_AUTO_TEST_CASE(list_replace_lvalue)/*{{{*/
{
    Teste obj(3);
    obj.name = "name1";
    list<Teste> objs;
    list<Teste>::iterator it = objs.insert(obj).first;

    obj.name = "name2";
    it = objs.replace(it, obj);
    
    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(objs.begin()->name, "name2");
    BOOST_CHECK_EQUAL(it->name, "name2");
    BOOST_CHECK_PREDICATE(std::not_equal_to<Teste*>(),(&obj)(&*objs.begin()));
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_replace_rvalue)/*{{{*/
{
    Teste obj(3);
    obj.name = "name1";
    list<Teste> objs;
    list<Teste>::iterator it = objs.insert(obj).first;

    it = objs.replace(it, Teste(4));
    
    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(objs.begin()->id, 4);
    BOOST_CHECK_EQUAL(objs.begin()->name, "");
    BOOST_CHECK_EQUAL(it->id, 4);
    BOOST_CHECK_EQUAL(it->name, "");
    BOOST_CHECK_PREDICATE(std::not_equal_to<Teste*>(),(&obj)(&*objs.begin()));
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_replace_rvalue_move)/*{{{*/
{
    Teste obj(3);
    obj.name = "name1";
    list<Teste> objs;
    list<Teste>::iterator it = objs.insert(obj).first;

    Teste obj4(4);
    obj4.dados = std::vector<int>(10,10);
    it = objs.replace(it, std::move(obj4));
    
    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(objs.begin()->id, 4);
    BOOST_CHECK_EQUAL(objs.begin()->name, "");
    BOOST_CHECK_EQUAL(objs.begin()->dados.size(), 10);
    BOOST_CHECK_EQUAL(obj4.dados.empty(), true);
    BOOST_CHECK_EQUAL(it->id, 4);
    BOOST_CHECK_EQUAL(it->name, "");
    BOOST_CHECK_PREDICATE(std::not_equal_to<Teste*>(),(&obj)(&*objs.begin()));
}/*}}}*/

BOOST_AUTO_TEST_CASE(list_copy)/*{{{*/
{
    Teste obj;
    list<Teste> objs;
    obj.name = "name1";
    objs.insert(obj);
    obj.name = "name2";
    objs.insert(obj);

    Teste obj2(3);
    obj2.name = "name3";
    objs.insert(obj);
    obj2.name = "name4";
    objs.insert(obj);

    list<Teste> objs2 = objs;
    BOOST_CHECK_EQUAL(objs, objs2);
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_assignment)/*{{{*/
{
    Teste obj;
    list<Teste> objs;
    obj.name = "name1";
    objs.insert(obj);
    obj.name = "name2";
    objs.insert(obj);

    Teste obj2(3);
    obj2.name = "name3";
    objs.insert(obj);
    obj2.name = "name4";
    objs.insert(obj);

    list<Teste> objs2;
    objs2 = objs;
    BOOST_CHECK_EQUAL(objs, objs2);
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_insert_multiplos_id0)/*{{{*/
{
    list<Teste> objs;

    Teste obj;
    obj.name = "name1";
    BOOST_CHECK_EQUAL(objs.insert(obj).second, true);
    obj.name = "name2";
    BOOST_CHECK_EQUAL(objs.insert(obj).second, true);
    obj.name = "name3";
    BOOST_CHECK_EQUAL(objs.insert(obj).second, true);

    BOOST_CHECK_EQUAL(objs.size(), 3);
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_insert_mesmo_id0_duas_vezes)/*{{{*/
{
    list<Teste> objs;

    std::shared_ptr<Teste> obj(new Teste);
    obj->name = "name1";
    BOOST_CHECK_EQUAL(objs.insert(obj).second, true);
    BOOST_CHECK_EQUAL(objs.insert(obj).second, false);

    BOOST_CHECK_EQUAL(objs.size(), 1);
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_insert_multiplos_ids_iguais)/*{{{*/
{
    list<Teste> objs;

    Teste obj(3);
    obj.name = "name1";
    objs.insert(obj);
    obj.name = "name2";
    BOOST_CHECK_EQUAL(objs.insert(obj).second, false);
    obj.name = "name3";
    BOOST_CHECK_EQUAL(objs.insert(obj).second, false);

    BOOST_CHECK_EQUAL(objs.size(), 1);
}/*}}}*/

#if 0
BOOST_AUTO_TEST_CASE(list_update)/*{{{*/
{
    std::shared_ptr<Teste> obj = Teste::create();
    obj->id = 3;
    obj->name = "name1";
    list<Teste> objs;
    objs.insert(*obj);

    obj->name = "rodolfo";
    objs.update(*obj);
    BOOST_CHECK_EQUAL(objs.begin()->name, "rodolfo");
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_armazena_sem_copia)/*{{{*/
{
    {
        list<const Teste> objs;
        std::shared_ptr<Teste> obj = Teste::create();
        obj->id = 1;
        obj->name = "name";

        objs.insert(*obj);
        BOOST_CHECK_EQUAL(&*obj, &*objs.begin());
    }
    {
        list<Teste> objs;
        std::shared_ptr<Teste> obj = Teste::create();
        obj->id = 1;
        obj->name = "name";
        objs.insert(*obj);
        BOOST_CHECK_EQUAL(&*obj, &*objs.begin());
    }
    {
        list<const Teste> objs;
        std::shared_ptr<Teste> obj = Teste::create();
        obj->id = 1;
        obj->name = "name";
        ::obj::testsuite::set_in_cache(*obj);
        objs.insert(*obj);
        BOOST_CHECK_EQUAL(&*obj, &*objs.begin());
    }
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_altera_item)/*{{{*/
{
    std::shared_ptr<Teste> obj = Teste::create();
    obj->id = 1;
    obj->name = "name1";

    list<Teste> objs;
    objs.insert(*obj);
    obj = obj->clone();
    obj->name = "name2";
    objs.update(*obj);
    BOOST_CHECK_EQUAL(*objs.begin(), *obj);
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_erase)/*{{{*/
{
    list<Teste> objs;
    std::shared_ptr<Teste> obj = Teste::create();
    obj->id = 3;
    obj->name = "name1";
    objs.insert(*obj);
    obj->id=4;
    obj->name = "name2";
    objs.insert(*obj);

    BOOST_CHECK_EQUAL(objs.erase(3), true);
    BOOST_CHECK_EQUAL(objs.size(), 1);
    BOOST_CHECK_EQUAL(objs.begin()->name, "name2");
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_erase_nao_existe)/*{{{*/
{
    list<Teste> objs;
    std::shared_ptr<Teste> obj = Teste::create();
    obj->id = 3;
    obj->name = "name1";
    objs.insert(*obj);
    obj = obj->clone();
    obj->id=4;
    obj->name = "name2";
    objs.insert(*obj);

    BOOST_CHECK_EQUAL(objs.erase(10), false);
    BOOST_CHECK_EQUAL(objs.size(),2);
    BOOST_CHECK_EQUAL(objs.begin()->name, "name1");
    BOOST_CHECK_EQUAL((++objs.begin())->name, "name2");
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_clone)/*{{{*/
{
    list<Teste> objs;
    for(unsigned i=0; i<10; ++i)
    {
        std::shared_ptr<Teste> obj = Teste::create();
        obj->id = i+1;
        obj->name = "name"+boost::lexical_cast<std::string>(i);
        objs.insert(*obj);
    }

    std::unique_ptr<list<Teste>> copia = objs.clone();
    BOOST_REQUIRE_EQUAL(copia->size(), objs.size());
    BOOST_FOREACH(const Teste &obj, *copia)
    {
        BOOST_CHECK_PREDICATE(std::not_equal_to<const Teste *>(),(&obj)(objs.at(obj.id).get()));
    }
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_replace)/*{{{*/
{
    list<Teste> objs;
    std::shared_ptr<Teste> disc = Teste::create();
    disc->name = "1";
    objs.insert(*disc);
    disc = disc->create();
    disc->name = "2";
    list<Teste>::iterator it = objs.insert(*disc).first;
    BOOST_CHECK_EQUAL(disc.use_count(), 2);

    std::shared_ptr<Teste> disc2 = disc->create();
    disc2->name = "3";
    it = objs.replace(it, *disc2);
    BOOST_CHECK_EQUAL(disc.use_count(), 1);
    BOOST_CHECK_EQUAL(&*it, &*disc2);
}/*}}}*/
BOOST_AUTO_TEST_CASE(list_replace_lah_existe)/*{{{*/
{
    list<Teste> objs;
    std::shared_ptr<Teste> disc = Teste::create();
    disc->name = "1";
    list<Teste>::iterator it = objs.insert(*disc).first;
    disc = disc->create();
    disc->name = "2";
    objs.insert(*disc);

    it = objs.replace(it, *disc);
    BOOST_CHECK_EQUAL(&*it, &*disc);
}/*}}}*/
#endif

